<template>
	<view>
		<view style="display: none;" class="tips color_fff size_12 align_c" :class="{ show: ajax.loading }" @tap="getHistoryMsg">{{ ajax.loadText }}</view>

		<view class="h208"></view>

		<view class="box-1" id="list-box">
			<view class="talk-list">
				<view class="itemWrap" v-for="(item, index) in talkList" :key="index" :id="`msg-${item.id}`">
					<!-- pull 收到-->
					<!-- push 发出 -->
					<!-- <view class="flex-cen">{{ $u.timeFrom(item.ucreateTime, false) }}</view> -->
					<!-- <view class="flex-cen">{{ $u.timeFormat(item.ucreateTime, 'yyyy年mm月dd日 hh时MM分ss秒') }}</view> -->
					<view class="flex-cen">
						<view class=" messageStyle">{{ $u.timeFormat(item.ucreateTime, 'hh:MM:ss') }}</view>
					</view>
					<view v-if="item.content" class="item flex_col" :class="item.from === from ? 'pull' : 'push'">
						<!-- <image :src="item.pic || avatar" mode="aspectFill" class="pic"></image> -->
						<u-avatar :src="item.pic || avatar"></u-avatar>
						<view class="content">{{ item.content }}</view>
					</view>
				</view>
			</view>
		</view>
		<view class="box-2" style="display: none;">
			<view class="flex_col">
				<view class="flex_grow">
					<input type="text" ref="ipt" class="content" v-model="content" placeholder="请输入聊天内容" placeholder-style="color:#DDD;" :cursor-spacing="6" />
				</view>
				<!-- @touchend.prevent="send" -->
				<button class="send" @click="send">发送</button>
			</view>
		</view>
	</view>
</template>

<script>
import {
	mapState, //先导入mapState方法
	mapMutations
} from 'vuex';
export default {
	data() {
		return {
			ajax: {
				rows: 20, //每页数量
				page: 1, //页码
				flag: true, // 请求开关
				loading: true, // 加载中
				loadText: '正在获取消息'
			},
			content: '',
			/* 消息来源 */
			from: '',

			/* websock */
			isSuccess: false,
			timer: '',
			isClose: false,
			sendMessage: {},
			connectNum: 1,

			/* 历史数据 */
			socketTask: null,
			his: '',
			talkList: [],
			/* 头像 */
			avatar: 'http://pic2.sc.chinaz.com/Files/pic/pic9/202002/hpic2119_s.jpg',
			/* 历史定时器 */
			historyTimer: ''
		};
	},
	computed: {
		...mapState('websocket', ['messageList', 'historyList'])
	},
	mounted() {
		this.$nextTick(() => {
			this.getHistoryMsg();
		});
	},
	onLoad(options) {
		console.log();
		let load = JSON.parse(options.query.data);
		/* 设置联系人标题 */
		this.setTitle(load.uremark);
		this.from = load.ufriendId;
	},
	// 监听页面卸载
	onHide() {
		let that = this;
		console.log('des');
		that.socketTask.close();
		clearInterval(that.timer);
		clearInterval(this.historyTimer);
	},
	onShow() {
		this.getWebsocketData();
		/* 连接web */
		// this.connectSocket();
		// this.historyTimer = setTimeout(() => {
		// 	let userInfo = uni.getStorageSync('userInfo');
		// 	let histroy = {
		// 		cmd: 19,
		// 		fromUserId: String(this.from),
		// 		userId: String(userInfo.userId),
		// 		type: 1
		// 	};
		// 	this.sendSocketMessage(JSON.stringify(histroy));
		// }, 2000);
	},
	onPageScroll(e) {
		if (e.scrollTop < 5) {
			this.getHistoryMsg();
		}
	},
	methods: {
		/* 设置联系人 姓名 */
		setTitle(title) {
			uni.setNavigationBarTitle({
				title
			});
		},

		// 获取历史消息
		getHistoryMsg() {
			if (!this.ajax.flag) {
				return; //
			}

			// 此处用到 ES7 的 async/await 知识，为使代码更加优美。不懂的请自行学习。
			let get = async () => {
				this.hideLoadTips();
				this.ajax.flag = false;
				let data = [];

				console.log('----- 模拟数据格式，供参考 -----');
				console.log(data); // 查看请求返回的数据结构

				// 获取待滚动元素选择器，解决插入数据后，滚动条定位时使用
				let selector = '';

				if (this.ajax.page > 1) {
					// 非第一页，则取历史消息数据的第一条信息元素
					selector = `#msg-${this.talkList[0].id}`;
				} else {
					// 第一页，则取当前消息数据的最后一条信息元素
					// selector = `#msg-${data[data.length - 1].id}`;
				}

				// 将获取到的消息数据合并到消息数组中
				this.talkList = [...data, ...this.talkList];

				// 数据挂载后执行，不懂的请自行阅读 Vue.js 文档对 Vue.nextTick 函数说明。
				this.$nextTick(() => {
					// 设置当前滚动的位置
					this.setPageScrollTo(selector);

					this.hideLoadTips(true);

					if (data.length < this.ajax.rows) {
						// 当前消息数据条数小于请求要求条数时，则无更多消息，不再允许请求。
						// 可在此处编写无更多消息数据时的逻辑
					} else {
						this.ajax.page++;

						// 延迟 200ms ，以保证设置窗口滚动已完成
						setTimeout(() => {
							this.ajax.flag = true;
						}, 200);
					}
				});
			};
			get();
		},
		// 拼接历史记录消息，正式项目可替换为请求历史记录接口
		joinHistoryMsg() {
			let join = async () => {
				let arr = [];
				let userInfo = uni.getStorageSync('userInfo');
				/* 历史消息 */
				let histroy = {
					cmd: 19,
					fromUserId: String(this.from),
					userId: String(userInfo.userId),
					// groupId: '群组id(此字段必须与userId一起使用,获取当前用户指定群组聊天消息),非必填',
					// beginTime: '消息区间开始时间Date毫秒数double类型,非必填',
					// endTime: '消息区间结束时间Date毫秒数double类型,非必填',
					// offset: '分页偏移量int类型，类似Limit 0,10 中的0,非必填',
					// count: '显示消息数量,类似Limit 0,10 中的10,非必填',
					// type: '消息类型(0:离线消息,1:历史消息)'
					type: 1
				};
				console.log(222);

				// await this.$store.dispatch('websocket/WEBSOCKET_SEND', JSON.stringify(histroy));

				// await (() => {
				// 	let name = String(this.from);
				// 	this.historyList['1631099885504274434'].forEach(i => {
				// 		arr.push({
				// 			id: i.id,
				// 			content: i.content,
				// 			time: i.createTime,
				// 			type: Math.random() > 0.5 ? 1 : 0 // 此为消息类别，设 1 为发出去的消息，0 为收到对方的消息,
				// 		});
				// 	});
				// 	arr.reverse();
				// 	console.log(666);
				// 	return arr;
				// })();

				//通过当前页码及页数，模拟数据内容
				// let startIndex = (this.ajax.page - 1) * this.ajax.rows;
				// let endIndex = startIndex + this.ajax.rows;
				// for (let i = startIndex; i < endIndex; i++) {
				// 	arr.push({
				// 		id: i, // 消息的ID
				// 		content: `这是历史记录的第${i + 1}条消息`, // 消息内容
				// 		type: Math.random() > 0.5 ? 1 : 0, // 此为消息类别，设 1 为发出去的消息，0 为收到对方的消息,
				// 		pic: '/static/logo.png' // 头像
				// 	});
				// }

				/*
						颠倒数组中元素的顺序。将最新的数据排在本次接口返回数据的最后面。
						后端接口按 消息的时间降序查找出当前页的数据后，再将本页数据按消息时间降序排序返回。
						这是数据的重点，因为页面滚动条和上拉加载历史的问题。
					 */
				// arr.reverse();

				// return arr;
			};

			// 此处用到 ES6 的 Promise 知识，不懂的请自行学习。
			return new Promise((done, fail) => {
				// 无数据请求接口，由 setTimeout 模拟，正式项目替换为 ajax 即可。
				setTimeout(() => {
					let data = join();
					done(data);
				}, 1500);
			});
		},
		// 设置页面滚动位置
		setPageScrollTo(selector) {
			let view = uni
				.createSelectorQuery()
				.in(this)
				.select(selector);
			view.boundingClientRect(res => {
				uni.pageScrollTo({
					scrollTop: res.top - 30, // -30 为多显示出大半个消息的高度，示意上面还有信息。
					duration: 0
				});
			}).exec();
		},
		// 隐藏加载提示
		hideLoadTips(flag) {
			if (flag) {
				this.ajax.loadText = '消息获取成功';
				setTimeout(() => {
					this.ajax.loading = false;
				}, 300);
			} else {
				this.ajax.loading = true;
				this.ajax.loadText = '正在获取消息';
			}
		},
		focus(e) {
			console.log(e);
		},

		/* long类型时间 */
		getTime() {
			var nowDate = new Date();
			var year = nowDate.getFullYear();
			var month = nowDate.getMonth();
			var today = nowDate.getDate();
			var hours = nowDate.getHours();
			var minutes = nowDate.getMinutes();
			var seconds = nowDate.getSeconds();

			if (month >= 1 && month <= 9) {
				month = '0' + month;
			}
			if (today >= 1 && today <= 9) {
				today = '0' + today;
			}
			var currentdate = year + '-' + month + '-' + today + ' ' + hours + ':' + minutes + ':' + seconds;
			console.log(currentdate);
			var currentDateLong = new Date(currentdate.replace(new RegExp('-', 'gm'), '/')).getTime();
			return currentDateLong;
		},
		scoketClose() {
			this.$socketIo.connectNum = 1;
			let userInfo = uni.getStorageSync('userInfo');
			const data = {
				cmd: 14,
				userId: userInfo.userId
			};
			this.$socketIo.send(data); // 这是给后端发送特定数据 关闭推送
			this.$socketIo.Close(); // 主动 关闭连接 ， 不会重连
		},
		getWebsocketData() {
			let userInfo = uni.getStorageSync('userInfo');
			// 要发送的数据包
			const data = {
				cmd: 19,
				fromUserId: String(this.from),
				userId: String(userInfo.userId),
				type: 1
			};
			// 打开连接
			this.$socketIo.connectSocketInit(data);
			// 接收数据
			uni.$on('getPositonsOrder', res => {
				this.connect = true;
				const { code, data } = res;
				console.log(res, 're');
				if (code == 10018) {
					let name = this.from;
					console.log(name, 'name');

					this.talkList = data.friends[name];
					// 根据后端传过来的数据进行 业务编写。。。
				} else {
				}
			});
			// 错误时做些什么
			uni.$on('connectError', () => {
				this.connect = false;
				this.scoketError = true;
			});
		},

		/* socketTask */
		connectSocket() {
			let that = this;
			let token = uni.getStorageSync('token') || 'c2FiZXI6c2FiZXJfc2VjcmV0';
			that.socketTask = uni.connectSocket({
				url: `wss://api.imquanzi.com/ws?token=${token}`,
				success(res) {
					console.log('socketTask连接成功');
					that.isSuccess = true;
				},
				fail(err) {
					console.log('报错', err);
				}
			});
			that.socketTask.onOpen(function(res) {
				that.connectNum = 1;
				console.log('socketTask连接已打开！');
				that.isSuccess = true;
				that.heart();
			});
			that.socketTask.onMessage(function(res) {
				console.log('收到服务器内容：' + res.data);
				that.handlerMsg(JSON.parse(res.data)); //这里是对获取到的数据进行操作
			});
			that.socketTask.onError(function(res) {
				console.log('socketTask连接打开失败，请检查！');
				that.isSuccess = false;
				// let numberTime = that.connectNum++;
				// console.log('失败重连' + this.numberTime);
				// if (that.connectNum > 6) {
				// 	uni.showToast({
				// 		title: '失败重连 超过6次 请重新连接websocket'
				// 	});
				// 	that.isClose = true;
				// 	return;
				// }
				// that.connectSocket();
				//进入重新连接
				that.reconnect();
			});
			// // 监听连接关闭 -
			that.socketTask.onClose(e => {
				console.log('socketTask连接关闭！');
				clearInterval(that.timer);
				that.timer = '';
				if (!that.isClose) {
					that.reconnect();
				}
			});
			console.log(that.socketTask, 'socketTask对象');
		},
		//进入重新连接
		reconnect() {
			let that = this;
			console.log('进入断线重连');
			// this.socketTask.close();
			that.socketTask = null;
			that.connectSocket();
		},
		//发送消息
		sendSocketMessage(msg) {
			console.log('发送信息');
			var that = this;
			console.log(msg);
			console.log(that.socketTask, 'that.socketTask');
			// debugger;
			return new Promise((reslove, reject) => {
				that.socketTask.send({
					data: msg,
					success(res) {
						console.log('发送成功');
						console.log(res, '成功的数据');
						reslove(res);
					},
					fail(res) {
						console.log('发送失败');
						console.log(res);
						console.log(res, '失败的数据');
						reject(res);
					}
				});
			});
		},
		handlerMsg(data) {
			console.log(data, '处理后的数据');
			if (data.command === 20) {
				let name = this.from;
				console.log(name, 'name');
				this.talkList = data.data.friends[name];
			}
		},
		//心跳
		heart() {
			let that = this;
			clearInterval(this.timer);
			this.timer = '';
			let userInfo = uni.getStorageSync('userInfo');
			// let msg = {
			// 	cmd: 19,
			// 	fromUserId: String(this.from),
			// 	userId: String(userInfo.userId),
			// 	// groupId: '群组id(此字段必须与userId一起使用,获取当前用户指定群组聊天消息),非必填',
			// 	// beginTime: '消息区间开始时间Date毫秒数double类型,非必填',
			// 	// endTime: '消息区间结束时间Date毫秒数double类型,非必填',
			// 	// offset: '分页偏移量int类型，类似Limit 0,10 中的0,非必填',
			// 	// count: '显示消息数量,类似Limit 0,10 中的10,非必填',
			// 	// type: '消息类型(0:离线消息,1:历史消息)'
			// 	type: 1
			// };
			let msg = {
				cmd: 13,
				hbbyte: '-127'
			};
			this.timer = setInterval(() => {
				that.sendSocketMessage(JSON.stringify(msg))
					.then(res => {
						console.log('心跳成功');
					})
					.catch(res => {
						console.log('发送失败');
						console.log(res);
					});
			}, 200000);
		},

		// 发送信息
		async send() {
			console.log(this.content, 'this.content');
			let userInfo = uni.getStorageSync('userInfo');
			/*
			{
			   "from": "来源ID",
			   "to": "目标ID",
			   "cmd":"命令码(11)int类型",
			   "createTime": "消息创建时间long类型",
			   "msgType": "消息类型int类型(0:text、1:image、2:voice、3:vedio、4:music、5:news)",
			   "chatType":"聊天类型int类型(0:未知,1:公聊,2:私聊)",
			   "groupId":"群组id仅在chatType为(1)时需要,String类型",
			   "content": "内容",
			   "extras" : "扩展字段,JSON对象格式如：{'扩展字段名称':'扩展字段value'}"
			}
			 */
			/* 发送消息服务的事件 */
			this.sendMessage = {
				from: String(userInfo.userId),
				to: String(this.from),
				cmd: 11,
				createTime: this.getTime(),
				msgType: 0,
				chatType: 2,
				content: this.content
			};
			console.log(this.sendMessage, 'this.sendMessage');
			// let socketRe = await this.$store.dispatch('websocket/WEBSOCKET_SEND', JSON.stringify(this.sendMessage));
			let socketRe = this.sendSocketMessage(JSON.stringify(this.sendMessage));
		}
	}
};
</script>

<style lang="scss">
// @import "../../lib/global.scss";
page {
	// background-color: #f3f3f3;
	font-size: 28rpx;
}

/* 加载数据提示 */
.tips {
	position: fixed;
	left: 0;
	top: var(--window-top);
	width: 100%;
	z-index: 9;
	background-color: rgba(0, 0, 0, 0.15);
	height: 72rpx;
	line-height: 72rpx;
	transform: translateY(-80rpx);
	transition: transform 0.3s ease-in-out 0s;

	&.show {
		transform: translateY(0);
	}
}

.box-1 {
	width: 100%;
	height: auto;
	padding-bottom: 100rpx;
	box-sizing: content-box;

	/* 兼容iPhoneX */
	margin-bottom: 0;
	margin-bottom: constant(safe-area-inset-bottom);
	margin-bottom: env(safe-area-inset-bottom);
}

.box-2 {
	position: fixed;
	left: 0;
	width: 100%;
	bottom: 0;
	height: auto;
	z-index: 2;
	border-top: #e5e5e5 solid 1px;
	box-sizing: content-box;
	background-color: #f3f3f3;

	/* 兼容iPhoneX */
	padding-bottom: 0;
	padding-bottom: constant(safe-area-inset-bottom);
	padding-bottom: env(safe-area-inset-bottom);

	> view {
		padding: 0 20rpx;
		height: 100rpx;
	}

	.content {
		background-color: #fff;
		height: 64rpx;
		padding: 0 20rpx;
		border-radius: 32rpx;
		font-size: 24rpx;
	}

	.send {
		background-color: #42b983;
		color: #fff;
		height: 64rpx;
		margin-left: 20rpx;
		border-radius: 32rpx;
		padding: 0;
		width: 120rpx;
		line-height: 62rpx;

		&:active {
			background-color: #5fc496;
		}
	}
}

.talk-list {
	.itemWrap {
		padding-bottom: 20rpx;
	}

	/* 消息项，基础类 */
	.item {
		padding: 20rpx 20rpx 0 20rpx;
		align-items: flex-start;
		align-content: flex-start;
		color: #333;

		.pic {
			width: 92rpx;
			height: 92rpx;
			border-radius: 50%;
			border: #fff solid 1px;
		}

		.content {
			padding: 20rpx;
			// padding-left: 42rpx;
			border-radius: 4px;
			max-width: 500rpx;
			min-width: 130rpx;
			word-break: break-all;
			line-height: 52rpx;
			// line-height: 24rpx;
			position: relative;
		}

		/* 收到的消息 */
		&.pull {
			.content {
				margin-left: 32rpx;
				background-color: #fff;
				border-radius: 20rpx 72rpx 72rpx 72rpx;
				font-size: 24rpx;
				font-family: PingFang SC-Medium, PingFang SC;
				font-weight: 500;
				color: #606060;
				&::after {
					// content: '';
					display: block;
					width: 0;
					height: 0;
					border-top: 16rpx solid transparent;
					border-bottom: 16rpx solid transparent;
					border-right: 20rpx solid #fff;
					position: absolute;
					top: 30rpx;
					left: -18rpx;
				}
			}
		}

		/* 发出的消息 */
		&.push {
			/* 主轴为水平方向，起点在右端。使不修改DOM结构，也能改变元素排列顺序 */
			flex-direction: row-reverse;

			.content {
				margin-right: 32rpx;
				background-color: #9d67f3;
				border-radius: 72rpx 20rpx 72rpx 72rpx !important;

				font-size: 24rpx;
				font-family: PingFang SC-Medium, PingFang SC;
				font-weight: 500;
				color: #ffffff;

				&::after {
					// content: '';
					display: block;
					width: 0;
					height: 0;
					border-top: 16rpx solid transparent;
					border-bottom: 16rpx solid transparent;
					border-left: 20rpx solid #a0e959;
					position: absolute;
					top: 30rpx;
					right: -18rpx;
				}
			}
		}
	}
}
</style>
